Gio._promisify(GnomeBluetooth.Client.prototype, 'connect_service');
+const STATE_CHANGE_FAILED_TIMEOUT_MS = 30 * 1000;
+
const BtClient = GObject.registerClass({
Properties: {
'available': GObject.ParamSpec.boolean('available', '', '',
this._client.connect('notify::default-adapter-powered', () => {
this.notify('active');
});
- this._client.connect('notify::default-adapter-state',
- () => this.notify('adapter-state'));
+ this._client.connect('notify::default-adapter-state', () => {
+ delete this._predictedState;
+ this.notify('adapter-state');
+ });
this._client.connect('notify::default-adapter', () => {
const newAdapter = this._client.default_adapter ?? null;
}
get adapter_state() {
+ if (this._predictedState !== undefined)
+ return this._predictedState;
return this._client.default_adapter_state;
}
toggleActive() {
- this._proxy.BluetoothAirplaneMode = this.active;
+ const {active} = this;
+
+ // on many systems, there's a significant delay until the rfkill
+ // state results in an adapter state change; work around that by
+ // overriding the current state with the expected transition
+ this._predictedState = active
+ ? AdapterState.TURNING_OFF
+ : AdapterState.TURNING_ON;
+ this.notify('adapter-state');
+
+ // toggling the state *really* should result in an adapter-state
+ // change eventually (even on error), but just to be sure to not
+ // be stuck with the overriden state, force a notify signal after
+ // a timeout
+ setTimeout(() => this._client.notify('default-adapter-state'),
+ STATE_CHANGE_FAILED_TIMEOUT_MS);
+
+ this._proxy.BluetoothAirplaneMode = active;
if (!this._client.default_adapter_powered)
this._client.default_adapter_powered = true;
}